/**
 * @fileOverview 抽象视图类
 * @author goodzsq@gmail.com
 */

var BaseObject = gg.module('BaseObject');

var interpolate = /\{\{(.+?)\}\}/g;

var View = BaseObject.extend({
    /**
     * @override
     */
    beforeInit: function() {
        this.children = [];
        this.node = this.createNode(this.config);
    },
    /**
     * @override
     */
    afterInit: function() {
        if (this.config.model) {
            this.setModel(gg.object(this.config.model));
        } else {
            this.startListening();
        }
        var children = this.config.children;
        if (gg.type(children) !== 'array') {
            children = [];
        }
        delete this.config.children;
        for (var i = 0; i < children.length; i++) {
            this.addChild(children[i]);
        }
    },
    /**
     * @override
     */
    destroy: function() {
        var child;
        while (child = this.children.pop()) {
            child.destroy();
        }
        this.destroyNode();
        this.node = null;
        View.__super__.destroy.call(this);
    },
    /**
     * @override
     * 表达式变量替换
     * @param {String} v 表达式
     */
    interpolateValue: function(v) {
        if (typeof v !== 'string') {
            return v;
        }
        var model = this.getModel();
        if (!model) {
            return v;
        }
        interpolate.lastIndex = 0;
        return v.replace(interpolate, function() {
            var name = arguments[1];
            if (model) {
                return model.get(name);
            }
            else {
                return "{{" + name + "}}";
            }
        });
    },
    /**
     * 获取模型 若无模型 则从祖先节点中取 递归调用
     */
    getModel: function() {
        if (this._model) {
            return this._model;
        } else if (this.parent) {
            return this.parent.getModel();
        } else {
            return null;
        }
    },
    /**
     * 设置模型 重新绑定模型监听
     * @param {Model} model
     */
    setModel: function(model) {
        if (this._model === model) {
            return;
        }
        //停止监听旧模型
        var oldModel = this.getModel();
        this.stopListening(oldModel);
        this._model = model;
        //开始监听新模型
        this.startListening();
    },
    /**
     * 刷新属性值 监听的模型属性发生变化时触发
     * @param {String} key 属性名称
     */
    refreshValue: function(key) {
        var rawValue = this.getRaw(key);
        var newValue = this.interpolateValue(rawValue);
        this.set(key, newValue);
    },
    /**
     * 重新绑定监听model的变化,包括
     */
    startListening: function() {
        var model = this.getModel();
        this.stopListening(this.getModel());
        var metadatas = this.constructor.metadata;
        var self = this, model = this.getModel();
        _.each(metadatas, function(metadata, key) {
            var rawValue = self.getRaw(key);
            var rs, resetFlag = false;
            interpolate.lastIndex = 0;
            while (rs = interpolate.exec(rawValue)) {
                resetFlag = true;
                model && self.listenTo(model, 'change:' + rs[1], function() {
                    self.refreshValue(key);
                });
            }
            //需要重新计算
            resetFlag && self.refreshValue(key);
        });
        //子节点对象重新绑定
        _.each(this.children, function(v, k) {
            v.startListening && v.startListening();
        });
    },
    /**
     * 当视图的属性变换时触发关联模型的更新
     * @param {String} key 属性值
     */
    updateModel: function(key) {
        var value = this.get(key);
        var rawValue = this.getRaw(key);
        interpolate.lastIndex = 0;
        var metadata, rs, model;
        if (rs = interpolate.exec(rawValue)) {
            if (model = this.getModel()) {
                if (metadata = model.constructor.metadata[rs[1]]) {
                    var DataType = gg.module('DataType.' + metadata.type);
                    if (DataType && DataType.parse) {
                        value = DataType.parse(value);
                    }
                }
                model.set(rs[1], value);
            }
        }
    },
    createNode: function(attrs) {
        gg.error('no implement createNode');
    },
    destroyNode: function() {
        gg.error('no implement destroyNode');
    },
    addChild: function(attr, index) {
        gg.error('no implement addChild');
    },
    removeChild: function(node) {
        gg.error('no implement removeChild');
    },
    removeChildAt: function(index) {

    },
    removeFromParent: function() {
        gg.error('no implement remove FromParent');
    }
});

module.exports = View;